using System;
using System.Collections;
using System.Text;
using Refly.CodeDom;
using Refly.CodeDom.Statements;
using Refly.CodeDom.Collections;
using Refly.Templates;
using Refly.CodeDom.Expressions;
using Doubler.Data;
using Doubler.Helpers;
using Doubler.Helpers.Graph;

namespace Doubler.Helpers
{
    public class GenerationHelper
    {

        public static string GetFieldName(IPropertyDeclaration Property)
        {
            string FieldName;
            FieldName = string.Format("_{0}", Property.Name);
            return FieldName;
        }

        public static PropertyFieldPair GeneratePropertyIndexerAndField(
            IClassDeclaration classDeclaration,
            string propertyName,
            Reflector.CodeModel.ITypeReference propertyType,
            Reflector.CodeModel.ITypeReference indexerType,
            bool Read,
            bool Write,
            System.CodeDom.MemberAttributes attributes)
        {
            IPropertyDeclaration Property = classDeclaration.AddIndexer(new StringTypeDeclaration(MetaHelper.GetFullTypeName(propertyType)), new StringTypeDeclaration(MetaHelper.GetFullTypeName(indexerType)));

            Property.Attributes = attributes;
            string FieldName = GenerationHelper.GetFieldName(Property);
            FieldDeclaration Field = classDeclaration.AddField(new StringTypeDeclaration(MetaHelper.GetFullTypeName(propertyType)), FieldName);

            if (Read)
            {
                Property.Get.Add(Stm.Return(Expr.This.Field(Field)));
            }
            if (Write)
            {
                Property.Set.Add(Stm.Assign(Expr.This.Field(Field), Expr.Value));
            }
            return new PropertyFieldPair(Property, Field);
        }

        public static PropertyFieldPair GeneratePropertyIndexerAndField(
            IClassDeclaration classDeclaration,
            string propertyName,
            ITypeDeclaration propertyType,
            ITypeDeclaration indexerType,
            bool Read,
            bool Write,
            System.CodeDom.MemberAttributes attributes)
        {
            IPropertyDeclaration Property = classDeclaration.AddIndexer(propertyType, indexerType);

            Property.Attributes = attributes;
            string FieldName = GenerationHelper.GetFieldName(Property);
            FieldDeclaration Field = classDeclaration.AddField(propertyType, FieldName);

            if (Read)
            {
                Property.Get.Add(Stm.Return(Expr.This.Field(Field)));
            }
            if (Write)
            {
                Property.Set.Add(Stm.Assign(Expr.This.Field(Field), Expr.Value));
            }
            return new PropertyFieldPair(Property, Field);
        }

        public static PropertyFieldPair GeneratePropertyAndField(IClassDeclaration classDeclaration, string propertyName, Reflector.CodeModel.ITypeReference propertyType, bool Read, bool Write, System.CodeDom.MemberAttributes attributes)
        {
            PropertyDeclaration Property = classDeclaration.AddProperty(new StringTypeDeclaration(MetaHelper.GetFullTypeName(propertyType)), propertyName);

            Property.Attributes = attributes;
            string FieldName = GenerationHelper.GetFieldName(Property);
            FieldDeclaration Field = classDeclaration.AddField(new StringTypeDeclaration(MetaHelper.GetFullTypeName(propertyType)), FieldName);

            if (Read)
            {
                Property.Get.Add(Stm.Return(Expr.This.Field(Field)));
            }
            if (Write)
            {
                Property.Set.Add(Stm.Assign(Expr.This.Field(Field), Expr.Value));
            }
            return new PropertyFieldPair(Property, Field);
        }

        public static PropertyDeclaration GeneratePropertyAgainstField(IClassDeclaration classDeclaration, string propertyName, Reflector.CodeModel.ITypeReference propertyType, bool Read, bool Write, System.CodeDom.MemberAttributes attributes, FieldDeclaration field)
        {
            PropertyDeclaration Property = classDeclaration.AddProperty(new StringTypeDeclaration(MetaHelper.GetFullTypeName(propertyType)), propertyName);

            Property.Attributes = attributes;
            if (Read)
            {
                Property.Get.Add(Stm.Return(Expr.This.Field(field)));
            }
            if (Write)
            {
                Property.Set.Add(Stm.Assign(Expr.This.Field(field), Expr.Value));
            }
            return Property;
        }

        public static PropertyFieldPair GeneratePropertyAndField(IClassDeclaration classDeclaration, string propertyName, ITypeDeclaration propertyType, bool Read, bool Write, System.CodeDom.MemberAttributes attributes)
        {
            PropertyDeclaration Property = classDeclaration.AddProperty(propertyType, propertyName);

            Property.Attributes = attributes;
            string FieldName = GenerationHelper.GetFieldName(Property);
            FieldDeclaration Field = classDeclaration.AddField(propertyType, FieldName);

            if (Read)
            {
                Property.Get.Add(Stm.Return(Expr.This.Field(Field)));
            }
            if (Write)
            {
                Property.Set.Add(Stm.Assign(Expr.This.Field(Field), Expr.Value));
            }
            return new PropertyFieldPair(Property, Field);
        }

        public static void GetSetterInfo(ref bool Write, ref Reflector.CodeModel.MethodVisibility Visability, Reflector.CodeModel.IPropertyDeclaration PropertyInformation)
        {
            EtterInfo(ref Write, ref Visability, PropertyInformation.SetMethod);
        }

        public static void GetGetterInfo(ref bool Read, ref Reflector.CodeModel.MethodVisibility Visability, Reflector.CodeModel.IPropertyDeclaration PropertyInformation)
        {
            EtterInfo(ref Read, ref Visability, PropertyInformation.GetMethod);
        }

        public static void EtterInfo(ref bool Access, ref Reflector.CodeModel.MethodVisibility Visability, Reflector.CodeModel.IMethodReference etter)
        {
            if (etter != null)
            {
                Reflector.CodeModel.IMethodDeclaration etterDec = etter.Resolve();
                bool Abstract = false;
                Abstract = etterDec.Abstract;
                if (Abstract)
                {
                    Access = true;
                    Visability = (etterDec.Visibility & Reflector.CodeModel.MethodVisibility.Public) | (etterDec.Visibility & Reflector.CodeModel.MethodVisibility.Private) | (etterDec.Visibility & Reflector.CodeModel.MethodVisibility.Family) | (etterDec.Visibility & Reflector.CodeModel.MethodVisibility.Assembly);
                }
            }
        }

    }
}
